package com.heu.blood.transfusion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.common.enums.TransfusionApplicationEnum;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.statistic.dao.DepartmentUseNumDao;
import com.heu.blood.statistic.entity.ApplyData;
import com.heu.blood.statistic.entity.DepartmentUseNum;
import com.heu.blood.transfusion.dao.TransfusionApplicationDao;
import com.heu.blood.transfusion.entity.TransfusionApplicationEntity;
import com.heu.blood.transfusion.service.TransfusionApplicationService;
import com.heu.blood.transfusion.vo.ABOTypeVo;
import com.heu.blood.transfusion.vo.BloodTypeInfo;
import com.heu.blood.transfusion.vo.TransfusionApplicationAnalysisVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Date;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.heu.blood.common.enums.CommonEnum.IF_SHOW;
import static com.heu.blood.common.enums.TransfusionApplicationEnum.IS_URGENT;

/**

 *
 * @author myq
 * @since 2023-07-01
 */
@Service
@Slf4j
public class TransfusionApplicationServiceImpl extends ServiceImpl<TransfusionApplicationDao, TransfusionApplicationEntity> implements TransfusionApplicationService {

    @Autowired
    private TransfusionApplicationDao transfusionApplicationDao;

    @Autowired
    private DepartmentUseNumDao departmentUseNumDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

            // 构造BloodInformationEntity对象
            TransfusionApplicationEntity transfusionApplication = new TransfusionApplicationEntity(); // 用于接收传递过来的TransfusionApplicationEntity参数
            if (Strings.isNotBlank((String) params.get("transfusionId"))){
                transfusionApplication.setTransfusionId((String) params.get("transfusionId")); // 添加transfusionId
            }
            if (Strings.isNotBlank((String) params.get("patientId"))){
                transfusionApplication.setPatientId((String) params.get("patientId")); // 添加patientId
            }
            if (Strings.isNotBlank((String) params.get("idcard"))){
                transfusionApplication.setIdcard((String) params.get("idcard")); // 添加idcard
            }
            if (Strings.isNotBlank((String) params.get("name"))){
                transfusionApplication.setName((String) params.get("name")); // 添加name
            }
            if (Strings.isNotBlank((String) params.get("appliedDoctor"))){
                transfusionApplication.setAppliedDoctor((String) params.get("appliedDoctor")); // 添加appliedDoctor
            }
            if (Strings.isNotBlank((String) params.get("applicationType"))){
                transfusionApplication.setApplicationType((String) params.get("applicationType")); // 添加applicationType
            }

            if (Strings.isNotBlank((String) params.get("aboBloodType"))){
                transfusionApplication.setAboBloodType((String) params.get("aboBloodType")); // 添加aboBloodType
            }
            if (Strings.isNotBlank((String) params.get("rhBloodType"))){
                transfusionApplication.setRhBloodType((String) params.get("rhBloodType")); // 添加rhBloodType
            }
            if (Strings.isNotBlank((String) params.get("bloodType"))){
                transfusionApplication.setBloodType((String) params.get("bloodType")); // 添加bloodType
            }
            if (Strings.isNotBlank((String) params.get("isUrgent"))){
                transfusionApplication.setIsUrgent((String) params.get("isUrgent")); // 添加isUrgent
            }
            if (Strings.isNotBlank((String) params.get("state"))){
                transfusionApplication.setState((String) params.get("state")); // 添加state
            }
            if (Strings.isNotBlank((String) params.get("transfusionStatus"))){
                transfusionApplication.setTransfusionStatus((String) params.get("transfusionStatus")); // 添加transfusionStatus
            }


            String applicationStartTime = (String)params.get("applicationStartTime");
            String applicationEndTime = (String)params.get("applicationEndTime");
            String transfusionStartTime = (String) params.get("transfusionStartTime");
            String transfusionEndTime = (String) params.get("transfusionEndTime");
            log.info(transfusionApplication.toString());

            // 构造条件构造器对象
            LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
            // 添加过滤条件
            queryWrapper.eq(Strings.isNotBlank(transfusionApplication.getTransfusionId()), TransfusionApplicationEntity::getTransfusionId, transfusionApplication.getTransfusionId())
                    .eq(Strings.isNotBlank(transfusionApplication.getPatientId()), TransfusionApplicationEntity::getPatientId, transfusionApplication.getPatientId())
                    .eq(Strings.isNotBlank(transfusionApplication.getAboBloodType()), TransfusionApplicationEntity::getAboBloodType, transfusionApplication.getAboBloodType())
                    .eq(Strings.isNotBlank(transfusionApplication.getRhBloodType()), TransfusionApplicationEntity::getRhBloodType, transfusionApplication.getRhBloodType())
                    .eq(Strings.isNotBlank(transfusionApplication.getBloodType()), TransfusionApplicationEntity::getBloodType, transfusionApplication.getBloodType())
                    .eq(Strings.isNotBlank(transfusionApplication.getIdcard()), TransfusionApplicationEntity::getIdcard, transfusionApplication.getIdcard())
                    .eq(Strings.isNotBlank(transfusionApplication.getName()), TransfusionApplicationEntity::getName, transfusionApplication.getName())
                    .eq(Strings.isNotBlank(transfusionApplication.getAppliedDoctor()), TransfusionApplicationEntity::getAppliedDoctor, transfusionApplication.getAppliedDoctor())
                    .eq(Strings.isNotBlank(transfusionApplication.getApplicationType()), TransfusionApplicationEntity::getApplicationType, transfusionApplication.getApplicationType())
                    .eq(Strings.isNotBlank(transfusionApplication.getState()), TransfusionApplicationEntity::getState, transfusionApplication.getState())
                    .eq(Strings.isNotBlank(transfusionApplication.getIsUrgent()), TransfusionApplicationEntity::getIsUrgent,IS_URGENT.code())
                    .eq(Strings.isNotBlank(String.valueOf(transfusionApplication.getIfShow())),TransfusionApplicationEntity::getIfShow,IF_SHOW.code())
                    .eq(Strings.isNotBlank(transfusionApplication.getTransfusionStatus()), TransfusionApplicationEntity::getTransfusionStatus, transfusionApplication.getTransfusionStatus())
                    .ge(Strings.isNotBlank(applicationStartTime), TransfusionApplicationEntity::getApplicationTime, applicationStartTime)
                    .le(Strings.isNotBlank(applicationEndTime),TransfusionApplicationEntity::getApplicationTime, applicationEndTime)
                    .ge(Strings.isNotBlank(transfusionStartTime), TransfusionApplicationEntity::getTransfusionTime, transfusionStartTime)
                    .le(Strings.isNotBlank(transfusionEndTime),TransfusionApplicationEntity::getTransfusionTime, transfusionEndTime);

            // 根据申请时间升序排列
            queryWrapper.orderByDesc(TransfusionApplicationEntity::getApplicationTime);
            IPage<TransfusionApplicationEntity> page = this.page(
                    new Query<TransfusionApplicationEntity>().getPage(params),
                    queryWrapper
            );

            return new PageUtils(page);
        }


    /**
     * 查询输血申请单信息
     * @param transfusionApplicationEntity
     * @return
     */
    @Override
    public List<TransfusionApplicationEntity> query(TransfusionApplicationEntity transfusionApplicationEntity) {
        // 构造条件构造器
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(transfusionApplicationEntity.getTransfusionId()), TransfusionApplicationEntity::getTransfusionId, transfusionApplicationEntity.getTransfusionId())
                .eq(Strings.isNotBlank(transfusionApplicationEntity.getPatientId()), TransfusionApplicationEntity::getPatientId, transfusionApplicationEntity.getPatientId())
                .eq(Strings.isNotBlank(transfusionApplicationEntity.getBloodType()), TransfusionApplicationEntity::getBloodType, transfusionApplicationEntity.getBloodType())
                .eq(Strings.isNotBlank(transfusionApplicationEntity.getAboBloodType()), TransfusionApplicationEntity::getAboBloodType, transfusionApplicationEntity.getAboBloodType())
                .eq(Strings.isNotBlank(transfusionApplicationEntity.getRhBloodType()), TransfusionApplicationEntity::getRhBloodType, transfusionApplicationEntity.getRhBloodType())
                .eq(Strings.isNotBlank(transfusionApplicationEntity.getTransfusionStatus()), TransfusionApplicationEntity::getTransfusionStatus, transfusionApplicationEntity.getTransfusionStatus())
                .eq(Strings.isNotBlank(String.valueOf(transfusionApplicationEntity.getIfShow())), TransfusionApplicationEntity::getIfShow,IF_SHOW.code());
        return transfusionApplicationDao.selectList(queryWrapper);
    }

    /**
     * 根据输血申请单号查询输血申请单信息
     * @param transfusionId
     * @return
     */
    @Override
    public TransfusionApplicationEntity queryByTransfusionId(String transfusionId) {
        // 构造queryWrapper对象
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(transfusionId), TransfusionApplicationEntity::getTransfusionId, transfusionId)
                .eq(TransfusionApplicationEntity::getIfShow,IF_SHOW.code());
        return transfusionApplicationDao.selectOne(queryWrapper);
    }

    /**
     * 多字段查询 开始时间结束时间，输血申请单号/姓名/申请输血类型/患者病历号
     * @param searchType
     * @param beginTime
     * @param endTime
     * @return
     */

    @Override
    public List<TransfusionApplicationEntity> selectKeyword(String searchType,String beginTime,String endTime) {
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (Strings.isNotBlank(beginTime)&&Strings.isNotBlank(endTime)) {
            queryWrapper.eq(TransfusionApplicationEntity::getIfShow,IF_SHOW.code())
                        .ge(Strings.isNotBlank(beginTime), TransfusionApplicationEntity::getApplicationTime, beginTime)
                        .le(Strings.isNotBlank(endTime), TransfusionApplicationEntity::getApplicationTime, endTime);
            if (Strings.isNotBlank(searchType)) {
                queryWrapper.and(wrapper ->
                        wrapper.like(TransfusionApplicationEntity::getTransfusionId, searchType)
                                .or()
                                .like(TransfusionApplicationEntity::getName, searchType)
                                .or()
                                .like(TransfusionApplicationEntity::getBloodType, searchType)
                                .or()
                                .like(TransfusionApplicationEntity::getPatientId,searchType)
                );
            }
        }else {
                    queryWrapper.eq(TransfusionApplicationEntity::getIfShow,IF_SHOW.code())
                            .like(Strings.isNotBlank(searchType),TransfusionApplicationEntity::getTransfusionId, searchType)
                            .or()
                            .like(Strings.isNotBlank(searchType),TransfusionApplicationEntity::getName, searchType)
                            .or()
                            .like(Strings.isNotBlank(searchType),TransfusionApplicationEntity::getBloodType, searchType);
        }
        return transfusionApplicationDao.selectList(queryWrapper);
    }

    /**
     * 获取当日的输血申请数
     */
    @Override
    public Integer getApplyNum() {
        // 获取当天的起始时间和结束时间
        LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

        // 创建lambdaQueryWrapper
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，使用日期范围查询
        queryWrapper.between(TransfusionApplicationEntity::getApplicationTime, startOfDay, endOfDay);

        // 使用count函数获取结果数量
        return transfusionApplicationDao.selectCount(queryWrapper);
    }

    /**
     * 获得指定日期的输血申请数
     * @param curDate
     * @return
     */
    @Override
    public Integer getApplyNum(LocalDate curDate) {
        // 获取当天的起始时间和结束时间
        LocalDateTime startOfDay = LocalDateTime.of(curDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(curDate, LocalTime.MAX);
        // 创建lambdaQueryWrapper
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，使用日期范围查询
        queryWrapper.between(TransfusionApplicationEntity::getApplicationTime, startOfDay, endOfDay);

        // 使用count函数获取结果数量
        return transfusionApplicationDao.selectCount(queryWrapper);
    }

    /**
     * 获得指定日期指定科室的输血申请数
     * @param curDate
     * @param code
     * @return
     */
    @Override
    public Integer getApplyNum(LocalDate curDate, String code) {
        // 获取当天的起始时间和结束时间
        LocalDateTime startOfDay = LocalDateTime.of(curDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(curDate, LocalTime.MAX);
        // 创建lambdaQueryWrapper
        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，使用日期范围查询
        queryWrapper.between(TransfusionApplicationEntity::getApplicationTime, startOfDay, endOfDay)
                    .eq(TransfusionApplicationEntity::getDepartment, code);

        // 使用count函数获取结果数量
        return transfusionApplicationDao.selectCount(queryWrapper);
    }

    /**
     * 获取七日用血申请单数
     * @return
     */
    @Override
    public List<ApplyData> getSevenDaysApply() {

        List<ApplyData> sevenDayApply = new ArrayList<>();
        // 获取当前时间
        LocalDate curDate = LocalDate.now();
        for (int i=6;i>=0;i--){
            LocalDate date = curDate.minusDays(i);
            int count = getApplyNum(date);
            Date sqlDate = Date.valueOf(date);
            ApplyData data = new ApplyData(sqlDate.toString(), count);
            sevenDayApply.add(data);
        }
        return sevenDayApply;
    }

    /**
     * 获取指定科室七日用血申请单数
     * @param code
     * @return
     */
    @Override
    public Integer getSevenDaysApplyNum(String code) {
        // 获取当前时间
        LocalDate curDate = LocalDate.now();
        // 七日总申请数
        int count = 0;
        for (int i=6;i>=0;i--){
            LocalDate date = curDate.minusDays(i);
            count += getApplyNum(date, code);
        }
        return count;
    }

    /**
     * 获取七日用血科室血量统计
     * @return
     */
    @Override
    public List<DepartmentUseNum> getSevenDaysDepartmentUseNum() {
        // 获取当前时间
        LocalDate curDate = LocalDate.now();
        LocalDateTime endOfDay = LocalDateTime.of(curDate, LocalTime.MAX);
        // 获取七天前的时间
        LocalDate sevenDaysBeforeDate = curDate.minusDays(6);
        LocalDateTime startOfDay = LocalDateTime.of(sevenDaysBeforeDate, LocalTime.MIN);
        return departmentUseNumDao.getSevenDaysDepartmentUseNum(startOfDay, endOfDay);
    }

    @Override
    public boolean updateTransfusionStateByTransfusionId(String transfusionId, String transfusionState) {
        LambdaUpdateWrapper<TransfusionApplicationEntity> updateWrapper = Wrappers.lambdaUpdate(TransfusionApplicationEntity.class)
                .eq(Strings.isNotBlank(transfusionId), TransfusionApplicationEntity::getTransfusionId, transfusionId)
                .set(Strings.isNotBlank(transfusionState), TransfusionApplicationEntity::getState, transfusionState);
        return baseMapper.update(null, updateWrapper) == 1;
    }

// 存储全部申请单汇总的Map 其中第一个String存储departmentCode 第二个Map<String,ABOTypeVo>中的String存储BloodType，
// ABOTypeVo存储A B AB O的数量及其单位
    private Map<String, Map<String, ABOTypeVo>> summary = new HashMap<>();

    private Map<String, ABOTypeVo> summaryWithoutDepartment = new HashMap<>();
    @Override
    public TransfusionApplicationAnalysisVo TransfusionApplicationAnalysis(Map<String, Object> params) {
        TransfusionApplicationAnalysisVo transfusionApplicationAnalysisVo = new TransfusionApplicationAnalysisVo();

        String applicationStartTime = (String)params.get("applicationStartTime");
        String applicationEndTime = (String)params.get("applicationEndTime");


        LambdaQueryWrapper<TransfusionApplicationEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(Strings.isNotBlank(applicationStartTime), TransfusionApplicationEntity::getApplicationTime, applicationStartTime)
                .le(Strings.isNotBlank(applicationEndTime), TransfusionApplicationEntity::getApplicationTime, applicationEndTime);

        List<TransfusionApplicationEntity> applications = transfusionApplicationDao.selectList(queryWrapper);
        summarizeApplications(applications);
//      已审核字段筛选
        queryWrapper.eq(TransfusionApplicationEntity::getTransfusionStatus, TransfusionApplicationEnum.REVIEW_APPROVAL.code());
        List<TransfusionApplicationEntity> applications2 = transfusionApplicationDao.selectList(queryWrapper);
        summarizeApplicationsWithoutDepartment(applications2);

        transfusionApplicationAnalysisVo.setSummary(summary);
        transfusionApplicationAnalysisVo.setSummaryWithoutDepartment(summaryWithoutDepartment);

        return transfusionApplicationAnalysisVo;
    }
//   全部申请单汇总
    private void summarizeApplications(List<TransfusionApplicationEntity> applications) {
        summary.clear();  // 清除之前的汇总数据
        for (TransfusionApplicationEntity application : applications) {
            addApplication(
                    application.getDepartment(),
                    application.getBloodType(),
                    application.getAboBloodType(),
                    application.getApplyCount(),
                    application.getMeasurementUnit()
            );
        }
    }
    //   全部申请单汇总不按照部门
    private void summarizeApplicationsWithoutDepartment(List<TransfusionApplicationEntity> applications) {
        summaryWithoutDepartment.clear();  // 清除之前的汇总数据
        for (TransfusionApplicationEntity application : applications) {
            addApplicationWithoutDepartment(
                    application.getBloodType(),
                    application.getAboBloodType(),
                    application.getApplyCount(),
                    application.getMeasurementUnit()
            );
        }
    }
//  同一科室、同一血液类型的A B AB O 加和
    private void addApplication(String department, String bloodType, String AboBloodType, BigDecimal quantity, String unit) {
        summary.computeIfAbsent(department, k -> new HashMap<>())
                .computeIfAbsent(bloodType, k -> new ABOTypeVo());

        ABOTypeVo aboTypeVo = summary.get(department).get(bloodType);
        switch (AboBloodType) {
            case "A":
                updateBloodTypeInfo(aboTypeVo.getTypeA(), quantity, unit);
                break;
            case "B":
                updateBloodTypeInfo(aboTypeVo.getTypeB(), quantity, unit);
                break;
            case "AB":
                updateBloodTypeInfo(aboTypeVo.getTypeAB(), quantity, unit);
                break;
            case "O":
                updateBloodTypeInfo(aboTypeVo.getTypeO(), quantity, unit);
                break;
        }
    }
// 不按照部门进行统计
    private void addApplicationWithoutDepartment(String bloodType, String AboBloodType, BigDecimal quantity, String unit) {
        summaryWithoutDepartment.computeIfAbsent(bloodType, k -> new ABOTypeVo());

        ABOTypeVo aboTypeVo = summaryWithoutDepartment.get(bloodType);

        switch (AboBloodType) {
            case "A":
                updateBloodTypeInfo(aboTypeVo.getTypeA(), quantity, unit);
                break;
            case "B":
                updateBloodTypeInfo(aboTypeVo.getTypeB(), quantity, unit);
                break;
            case "AB":
                updateBloodTypeInfo(aboTypeVo.getTypeAB(), quantity, unit);
                break;
            case "O":
                updateBloodTypeInfo(aboTypeVo.getTypeO(), quantity, unit);
                break;
        }
    }

    private void updateBloodTypeInfo(BloodTypeInfo bloodTypeInfo, BigDecimal quantity, String unit) {
        bloodTypeInfo.setQuantity(bloodTypeInfo.getQuantity().add(quantity));
        bloodTypeInfo.setUnit(unit);
    }

    @Override
    public Map<String, Map<String, ABOTypeVo>> getSummary() {
        return summary;
    }

    @Override
    public Map<String, ABOTypeVo> getSummarizeApplicationsWithoutDepartment() {
        return summaryWithoutDepartment;
    }


}
